#include <stdio.h>
#include <linux/ioctl.h>
#include <sys/soundcard.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/time.h>

#define SAMPLERATE     48000 //定义采样率
#define READMSFORONCE    10 //采样周期(ms)

#define BUFFERNODECOUNT       12800 //链表节点个数

#define AUDIOREADDEV    "/dev/dsp"
#define AUDIOWRITEDEV   "/dev/dsp1"

char audioreaddev[30]  = AUDIOREADDEV;
char audiowritedev[30] = AUDIOWRITEDEV;

//char buffer[SAMPLERATE/1000*READMSFORONCE*sizeof(short)];
struct AudioBuffer;
typedef struct AudioBuffer
{
    unsigned char buffer[SAMPLERATE/1000*READMSFORONCE*sizeof(short)];
    struct AudioBuffer  *pNext;
} AUDIOBUFFER;
AUDIOBUFFER audiobuffer[BUFFERNODECOUNT];
AUDIOBUFFER *pWriteHeader = NULL;
AUDIOBUFFER *pReadHeader = NULL;

int BufferCount = 0;//链表节点个数
pthread_mutex_t mutex_lock;

int Frequency = SAMPLERATE;
int format = AFMT_S16_LE;
int channels = 1;
int setting = 0x00080009;

sem_t sem_capture;
sem_t sem_play;

struct timeval tv;
struct timezone tz;

void * read_from_soundcard(void *para)
{
    int fdsound = 0;

    fdsound = open(audioreaddev, O_RDONLY);
    if(fdsound<0)
    {
       perror("open audio device read only");
       return NULL;
    }    

    printf("setting %s paraments\n", audioreaddev);
    ioctl(fdsound, SNDCTL_DSP_SPEED, &Frequency);//采样频率
    ioctl(fdsound, SNDCTL_DSP_SETFMT, &format);//音频设备位宽
    ioctl(fdsound, SNDCTL_DSP_CHANNELS, &channels);//音频设备通道
    ioctl(fdsound, SNDCTL_DSP_SETFRAGMENT, &setting);//采样缓冲区

    while(1)
    {
        if(read(fdsound, pWriteHeader->buffer, sizeof(pWriteHeader->buffer)) < 0)
        {
            perror("read soundcard");
        }
        else
        {


			pthread_mutex_lock(&mutex_lock);
			BufferCount++;
			pthread_mutex_unlock(&mutex_lock);
            pWriteHeader = pWriteHeader->pNext;

			if(BufferCount > 5)
			{
	            sem_post(&sem_capture);
	            sem_post(&sem_capture);
	            sem_post(&sem_capture);
	            sem_post(&sem_capture);
	            sem_post(&sem_capture);
			}
        }
#if 0
		if (BufferCount > 100) 
		{
			printf("send sem\n");
			sem_post(&sem_play);
			break;
		}
#endif
    }

    close(fdsound);
}

void * write_to_soundcard(void *para)
{
    int fdsoundplay = 0;
	static int FrameNO = 0;
	int count_sync = 0;

    fdsoundplay = open(audiowritedev, O_WRONLY);/*只写方式打开设备*/
    if(fdsoundplay<0)
    {
       perror("open audio device write only");
       return NULL;
    }

    printf("setting %s paraments\n", audiowritedev);
    ioctl(fdsoundplay, SNDCTL_DSP_SPEED, &Frequency);//采样频率
    ioctl(fdsoundplay, SNDCTL_DSP_SETFMT, &format);//音频设备位宽
    ioctl(fdsoundplay, SNDCTL_DSP_CHANNELS, &channels);//音频设备通道
    ioctl(fdsoundplay, SNDCTL_DSP_SETFRAGMENT, &setting);//采样缓冲区

#if 0
	sem_wait(&sem_play);
#endif
    while(1)
    {
        sem_wait(&sem_capture);
		gettimeofday(&tv, &tz);

		#if 0
		if(BufferCount > 10)
		{
			count_sync = 1;
		}
		else if(BufferCount > 5)
		{
			count_sync = 1;
		}
		else if(BufferCount < 2)
		{
			count_sync = 5;
		}
		#endif
		//count_sync = 0;


		if(BufferCount > 0)
		{
		    if(write(fdsoundplay, pReadHeader->buffer, sizeof(pReadHeader->buffer)) < 0)
		    {    
		        perror("write soundcard\n");
		    }
		    else
		    {
				printf("%ld,%6ld, %5d,%ld,%d,%d\n", tv.tv_sec, tv.tv_usec, FrameNO++, tv.tv_sec*1000+tv.tv_usec/1000, BufferCount, count_sync);
				pthread_mutex_lock(&mutex_lock);
				BufferCount--;
				pthread_mutex_unlock(&mutex_lock);
		        pReadHeader = pReadHeader->pNext;
		    }
		}
    }

    close(fdsoundplay);
}

int main(int argc, char **argv)
{
    FILE *fprecord = NULL;
    int i;
    int  iret1, iret2;
    pthread_t thread1, thread2;

    sem_init(&sem_capture, 0, 0);
	sem_init(&sem_play, 0, 0);
	pthread_mutex_init(&mutex_lock, NULL);

    for(i=0;i<BUFFERNODECOUNT-1;i++)
    {
        audiobuffer[i].pNext = &audiobuffer[i+1];
    }
    audiobuffer[BUFFERNODECOUNT-1].pNext = &audiobuffer[0];
    pWriteHeader = &audiobuffer[0];
    pReadHeader  = &audiobuffer[0];

	printf("SAMPLERATE/1000*READMSFORONCE*sizeof(short)=%d\n", SAMPLERATE/1000*READMSFORONCE*sizeof(short));

	iret1 = pthread_create( &thread1, NULL, read_from_soundcard, (void*) NULL);
    usleep(10000);
	iret2 = pthread_create( &thread2, NULL, write_to_soundcard, (void*) NULL);
	pthread_join( thread1, NULL);
	pthread_join( thread2, NULL);

}
